home *** CD-ROM | disk | FTP | other *** search
Wrap
{$C-,I-,V-,R-,K-} {++++++++++++++++++++++++++++++++++++++++++++++++++++++++} {+ +} {+ PROGRAM TITLE: Cross Reference Generator +} {+ +} {+ WRITTEN BY: Peter Grogono +} {+ DATE WRITTEN: ? +} {+ +} {+ SUMMARY: +} {+ 1. Output Files: +} {+ a. first output file is a numbered listing +} {+ of the input source +} {+ b. second output file is cross reference +} {+ with each identifier followed by the +} {+ line numbers on which it appears. +} {+ 2. Listing Device: +} {+ The numbered source listing may optionally +} {+ be routed to the screen or printer (but not +} {+ both). +} {+ +} {+ MODIFICATION RECORD: +} {+ 17-APR-84 -Modified for Turbo Pascal so +} {+ $ includes are supported +} {+ +} {+ +} {++++++++++++++++++++++++++++++++++++++++++++++++++++++++} PROGRAM XREFG2; { Cross Reference Generator } CONST alfa_length = 15; dflt_str_len = 255; entrygap = 0; { # of blank lines between line numbers} heading : string[23] = 'Cross-Reference Listing'; headingsize = 3; {number of lines for heading} LLmax = dflt_str_len; MaxOnLine = 8; Maxlines = MAXINT; {longest document permitted} MaxWordlen = alfa_length;{longest word read without truncation} Maxlinelen = 80; {length of output line} MaxOnPage = 60; {size of output page} NumKeys = 70; {number of Pascal reseve words} {Read your Pascal manuals on this one!} NumberWidth = 6; space : char = ' '; TYPE ALFA = string[alfa_length]; CHARNAME = (lletter, uletter, digit, blank, quote, atab, EndOfLine, FileMark, otherchar ); CHARINFO = RECORD name : charname; valu : CHAR END; COUNTER = 1..Maxlines; pageindex = BYTE; Wordindex = 1..MaxWordlen; Queuepointer = ^Queueitem; Queueitem = RECORD linenumber : counter; NextInQueue: Queuepointer END; EntryType = RECORD Wordvalue : alfa; FirstInQueue, lastinQueue: Queuepointer END; treepointer = ^node; node = RECORD entry : EntryType; left, right : treepointer END; GenStr = string[255]; VAR bell : CHAR; fatal_error : BOOLEAN; FILE_ID, { Input file name } PRN_ID, { basic file name + '.PRN' } New_ID : string[20]; { basic file name + '.XRF' } form_feed : CHAR; Key : ARRAY[1..NumKeys] OF alfa; LISTING : BOOLEAN; tab : CHAR; WordTree : treepointer; GAP : char ; Currentline: INTEGER; FOUT: TEXT; { print output file } XOUT: TEXT; { xref output file } PROCEDURE PAGE(VAR fx: TEXT); BEGIN WRITELN(fx); WRITE(fx, form_feed); END; { FUNCTYPE: } { Do binary search for keyword in 'key' list. If found, return } { TRUE, else FALSE. } Function Find_in_Reserve(var kword: alfa) : boolean; Label Return; Var low, high, mid : integer; Begin low := 1; high := NUMKEYS; while (low <= high) do begin mid := (low+high) div 2; if kword < key[mid] then high := mid - 1 else if kword > key[mid] then low := mid + 1 else begin Find_in_Reserve := TRUE; goto Return; end; end; Find_in_Reserve := FALSE; Return: End; PROCEDURE BuildTree(VAR tree: treepointer; VAR INFILE: GenStr); VAR CurrentWord : alfa; FIN : TEXT; { local input file } currchar, { Current operative character } nextchar : charinfo; { Look-ahead character } flushing : (KNOT, DBL, STD, LIT, SCANFN, SCANFN2); fname : string[30]; DoInclude : boolean; { TRUE if we discovered include file } fbuffer : string[255]; { Format buffer - before final Print } LineIn : string[255]; LineInLast : string[255]; cp : 0..255; xeof, { EOF status AFTER a read } xeoln : BOOLEAN; { EOLN status after a read } PROCEDURE Entertree(VAR subtree: treepointer; Word : alfa; line :counter); VAR nextitem : Queuepointer; BEGIN IF subtree=nil THEN BEGIN {create a new entry} NEW(subtree); WITH subtree^ DO BEGIN left := nil; right := nil; WITH entry DO BEGIN Wordvalue := Word; NEW(FirstInQueue); LastinQueue := FirstInQueue; WITH FirstInQueue^ DO BEGIN linenumber := line; NextInQueue := nil; END;{WITH FirstInQueue} END;{WITH entry} END;{WITH subtree} END {create a new entry} ELSE {append a list item} WITH subtree^, entry DO IF Word=Wordvalue THEN BEGIN IF lastinQueue^.linenumber <> line THEN BEGIN NEW(nextitem); WITH Nextitem^ DO BEGIN linenumber := line; NextInQueue := nil; END;{WITH} lastinQueue^.NextInQueue := Nextitem; lastinQueue := nextitem; END; END ELSE IF Word < Wordvalue THEN Entertree(left,Word,line) ELSE Entertree(right,Word,line); END;{Entertree} Procedure ReadC({updating} VAR nextchar : charinfo; {returning}VAR currchar : charinfo ); Var Look : char; { Character read in from File } BEGIN {+++ File status module. +++ Stores file status "AFTER" a read. NOTE this play on words - after one char is actually "PRIOR TO" the next character } if xeoln then begin LineInLast := LineIn; if (not EOF(FIN)) then begin readln(FIN, LineIn); cp := 0; xeoln := FALSE; end else xeof := TRUE; end; if cp >= length(LineIn) then begin xeoln := TRUE; xeof := EOF(FIN); Look := ' '; end else begin cp := cp + 1; Look := LineIn[cp]; End; {+++ current operative character module +++} currchar := nextchar; {+++ Classify the character just read +++} WITH nextchar DO BEGIN{ Look-ahead character name module } IF xeof THEN name := FileMark ELSE IF xeoln THEN name := EndOfLine ELSE IF Look IN ['a'..'z'] THEN {lower case plus} name := lletter ELSE IF Look IN ['^','$','_','A'..'Z'] THEN {upper case} name := uletter ELSE IF Look IN ['0'..'9'] THEN {digit} name := digit ELSE IF Look = '''' THEN name := quote ELSE IF Look = TAB THEN name := atab ELSE IF Look = space THEN name := blank ELSE name := otherchar; CASE name of{ store character value module } EndOfLine, FileMark: Valu := space; lletter: Valu := upcase(look); { Cnvrt to uppcase } ELSE valu := look; END{ case name of }; End{ Look-ahead character name module }; END; {of ReadC} PROCEDURE GetL( VAR fbuffer : GenStr ); {++++++++++++++++++++++++++++++++++++++++++++++++++++++++} {+ Get a line of text into users buffer. +} {+ Flushes comment lines: +} {+ Flushes lines of Literals: 'this is it' +} {+ Ignores special characters & tabs: +} {+ Recognizes End of File and End of Line. +} {+ +} {+GLOBAL +} {+ flushing : (KNOT, DBL, STD, LIT, SCANFN); +} {+ LLmax = 0..Max Line length; +} {++++++++++++++++++++++++++++++++++++++++++++++++++++++++} VAR state : (scanning, terminal, overflow); sawdot : boolean; BEGIN { GetL } fbuffer := ''; fname := ''; fatal_error := FALSE; state := scanning; REPEAT ReadC(nextchar, currchar); IF (length(fbuffer) >= LLmax) THEN{ exceeded length of buffer } BEGIN{ reset EOLN } fatal_error := TRUE; state := overflow; fbuffer := ''; WRITE(bell); WRITELN('EXCEEDED LENGTH OF INPUT BUFFER'); END ELSE BEGIN IF (currchar.name IN [FileMark,EndOfLine]) THEN state:=terminal{ END of line or END of file }; CASE flushing of KNOT: CASE currchar.name of lletter, uletter, digit, blank: BEGIN{ store } fbuffer := concat(FBUFFER,CURRCHAR.VALU) ; END; atab, quote, otherchar: BEGIN{ Flush comments -convert tabs & other chars to spaces } IF (currchar.valu='(') and (nextchar.valu='*') THEN flushing := DBL ELSE IF (currchar.valu='{') THEN flushing := STD ELSE IF currchar.name=quote THEN flushing := LIT; { convert to a space } fbuffer := concat(fbuffer,GAP); END; ELSE { END of line -or- file mark } fbuffer := concat(fbuffer,currchar.valu) END{ case currchar name of }; DBL: { scanning for a closing - double comment } IF (currchar.valu ='*') and (nextchar.valu =')') THEN flushing := KNOT; STD: begin { scanning for a closing curley } IF currchar.valu = '}' THEN flushing := KNOT; { Check if incl } if (currchar.valu = '$') and (nextchar.valu = 'I') then flushing := SCANFN; end; LIT: { scanning for a closing quote } IF currchar.name = quote THEN flushing := KNOT; SCANFN: if (nextchar.valu<>' ') and (nextchar.valu<>TAB) then begin flushing := SCANFN2; SAWDOT := FALSE; end; SCANFN2: if (currchar.valu in ['A'..'Z','0'..'9','.']) then begin fname := concat(fname, currchar.valu); if currchar.valu = '.' then SAWDOT := TRUE; end else begin if length(fname) = 0 then { Make sure we ignore $I-} DoInclude := FALSE { compiler directive } else begin if not SAWDOT then fname := Concat(fname, '.PAS'); DoInclude := TRUE; end; flushing := STD; end; END{ flushing case } END{ ELSE } UNTIL (state<>scanning); END; {of GetL} PROCEDURE ReadWord; {++++++++++++++++++++++++++++++++++++++++++++++++} {+ +} {+ Analyze the Line into "words" +} {+ +} {++++++++++++++++++++++++++++++++++++++++++++++++} LABEL 1; VAR ix, {temp indexer} idlen, {length of the word} Cpos : BYTE; { Current Position pointer } BEGIN{ ReadWord } Cpos := 1; { start at the beginning of a line } WHILE Cpos < length(fbuffer) DO BEGIN {Cpos<length(fbuffer)} WHILE (Cpos < length(fbuffer)) AND (fbuffer[Cpos]=space) DO Cpos:=Cpos + 1; {--- skip spaces ---} idlen := 0; WHILE (Cpos < length(fbuffer)) AND (fbuffer[Cpos ] <> space) DO BEGIN{ accept only non-spaces } IF idlen < MaxWordlen THEN BEGIN idlen := idlen + 1; CurrentWord[idlen] := fbuffer[Cpos]; END; Cpos := Cpos +1; END{ WHILE }; CurrentWord[0] := chr(idlen); IF length(CurrentWord)=0 THEN {no word was found} GOTO 1; IF (not Find_in_Reserve(CurrentWord)) and {check if reserved word} (not (CurrentWord[1] in ['0'..'9'])) then {or numeric constant} EnterTree(tree,CurrentWord,Currentline); 1:{Here is no word <length of word=0>}; END; {WHILE Cpos<length(fbuffer)} END; {of Readword} BEGIN{BuildTree} flushing := KNOT{ flushing }; DoInclude := FALSE; xeoln := TRUE; xeof := FALSE; LineIn := ''; ASSIGN(FIN,INFILE); RESET(FIN); IF IOresult <> 0 THEN BEGIN WRITE(BELL); WRITELN('File ',INFILE,' not found !!!!!!'); fatal_error := TRUE; END; nextchar.name := blank; { Initialize next char to a space } nextchar.valu := space; ReadC({update} nextchar, { Initialize current char to space } {returning} currchar); { First char from file in nextchar } WHILE ((currchar.name<>filemark) AND (NOT fatal_error)) DO BEGIN Currentline := Currentline + 1; GetL(fbuffer) { attempt to read the first line }; Writeln(Fout, Currentline:6,': ',LineInLast); IF listing THEN Writeln(Currentline:6,': ',LineInLast) else if (Currentline mod 100) = 0 then writeln('ON LINE : ',Currentline:0); ReadWord; {Analyze the Text into single 'words' } if DoInclude then Begin BuildTree(tree, fname); { recursively do include } DoInclude := FALSE; end; END; {While} close(FIN); END; {of BuildTree}{CLOSE(PRN_ID);} PROCEDURE PrintTree(tree: treepointer); { GLOBAL MaxOnLine = max line references per line NumberWidth = field for each number } VAR pageposition: pageindex; PROCEDURE PrintEntry(subtree: treepointer; VAR position: pageindex); VAR ix: Wordindex; itemcount : 0..Maxlinelen; itemptr : Queuepointer; PROCEDURE PrintLine(VAR Currentposition: pageindex; newlines: pageindex); VAR linecounter: pageindex; BEGIN IF (Currentposition + newlines) < MaxOnPage THEN BEGIN FOR linecounter:=1 TO newlines DO WRITELN(XOUT); Currentposition := Currentposition + newlines; END ELSE BEGIN PAGE(XOUT); WRITELN(XOUT,heading); FOR linecounter := 1 TO headingsize - 1 DO WRITELN(XOUT); Currentposition := headingsize + 1; END END;{PrintLine} BEGIN{PrintEntry} IF subtree<>nil THEN WITH subtree^ DO BEGIN PrintEntry(left,position); PrintLine(position,entrygap + 1); WITH entry DO BEGIN FOR ix := 1 to length(WordValue) do WRITE(XOUT, WordValue[ix]); WRITE(XOUT, space:(MaxWordLen-length(WordValue))); itemcount := 0; itemptr := FirstInQueue; WHILE itemptr <> nil DO BEGIN itemcount := itemcount + 1; IF itemcount > MaxOnLine THEN BEGIN PrintLine(position,1); WRITE(XOUT, space:MaxWordlen); itemcount := 1; END; WRITE(XOUT, itemptr^.linenumber: numberwidth); itemptr := itemptr^.NextInQueue; END;{WHILE} END; {WITH entry} PrintEntry(right,position); END; {WITH subtree^} END; {PrintEntry} BEGIN{PrintTree} PagePosition := MaxOnPage; PrintEntry(tree,PagePosition); END; {of PrintTree}{CLOSE(New_ID);} FUNCTION ConnectFiles: boolean; TYPE Linebuffer = string[80]; VAR ix : BYTE; BEGIN{ ConnectFiles } fatal_error := FALSE; ConnectFiles := TRUE; WRITELN('Enter Complete Filenames') ; WRITELN ; WRITE('Input File: '); READLN(FILE_ID); WRITELN; WRITE('Printed output: '); READLN(PRN_ID); WRITELN; WRITE('Cross-Reference output: '); READLN(NEW_ID); WRITELN; Assign(fout,PRN_ID); Rewrite(FOUT); if IOresult <> 0 then begin writeln('Could not open ',PRN_ID,' (print output file).'); ConnectFiles := FALSE; fatal_error := TRUE; end; assign(xout,NEW_ID); Rewrite(Xout) ; if IOresult <> 0 then begin writeln('Could not open ',NEW_ID,' (xref output file).'); ConnectFiles := FALSE; fatal_error := TRUE; end; END{ of ConnectFiles }; PROCEDURE Initialize; VAR Ch: CHAR; BEGIN bell := ^G; GAP := ' ' ; Currentline := 0; IF ConnectFiles THEN BEGIN Key[ 1] := 'ABSOLUTE'; Key[ 2] := 'AND'; Key[ 3] := 'ARRAY'; Key[ 4] := 'ASSIGN'; Key[ 5] := 'BEGIN'; Key[ 6] := 'BOOLEAN'; Key[ 7] := 'BYTE'; Key[ 8] := 'CASE'; Key[ 9] := 'CHAIN'; Key[10] := 'CHAR'; Key[11] := 'CHR'; Key[12] := 'CLOSE'; Key[13] := 'CONCAT'; Key[14] := 'CONST'; Key[15] := 'COPY'; Key[16] := 'DELETE'; Key[17] := 'DIV'; Key[18] := 'DO'; Key[19] := 'DOWNTO'; Key[20] := 'ELSE'; Key[21] := 'END'; Key[22] := 'EOF'; Key[23] := 'EOLN'; Key[24] := 'EXECUTE'; Key[25] := 'EXIT'; Key[26] := 'EXTERNAL'; Key[27] := 'FALSE'; Key[28] := 'FILE'; Key[29] := 'FILLCHAR'; Key[30] := 'FOR'; Key[31] := 'FORWARD'; Key[32] := 'FUNCTION'; Key[33] := 'GOTO'; Key[34] := 'IF'; Key[35] := 'IN'; Key[36] := 'INLINE'; Key[37] := 'INPUT'; Key[38] := 'INTEGER'; Key[39] := 'LABEL'; Key[40] := 'LENGTH'; Key[41] := 'MOD'; Key[42] := 'NIL'; Key[43] := 'NOT'; Key[44] := 'OF'; Key[45] := 'OR'; Key[46] := 'ORD'; Key[47] := 'OUTPUT'; Key[48] := 'PACKED'; Key[49] := 'PROCEDURE'; Key[50] := 'PROGRAM'; Key[51] := 'REAL'; Key[52] := 'RECORD'; Key[53] := 'REPEAT'; Key[54] := 'SET'; Key[55] := 'SHL'; Key[56] := 'SHR'; Key[57] := 'STRING'; Key[58] := 'SUCC'; Key[59] := 'TEXT'; Key[60] := 'THEN'; Key[61] := 'TO'; Key[62] := 'TRUE'; Key[63] := 'TYPE'; Key[64] := 'UNTIL'; Key[65] := 'VAR'; Key[66] := 'WHILE'; Key[67] := 'WITH'; Key[68] := 'WRITE'; Key[69] := 'WRITELN'; Key[70] := 'XOR'; tab := CHR(9); { ASCII Tab character } form_feed := CHR(12); gap := CHR(32); WRITE('List file to console (Y/N)?: '); READ(kbd,Ch); LISTING := ( (Ch='Y') OR (Ch='y') ); WRITELN; WRITELN; END; {IF ConnectFiles} END; {of Initialize} BEGIN { Cross Reference } CLRSCR; WRITELN(' ':22, 'CROSS REFEREN']Wlaeiu.tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo;e;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Ee= so oo oGs(= Cioyoo oG; ; ; ; eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE;a; o; E Rci N 1R;a=oeR E n; ; ; oGs'an E;at X a 'o;iIttttttttttttttttttttttttttttttttu] ;a; o; E nlae= l;nR;a e= p so ; 'anros'an Ewoo oG; ; ; ub 1eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee;a; o; E Rci N 1R;a=oeR eEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE;a; mfVbf (p'oyE a 'o;iE;n1uoe;iE;a o; E nlae= l;nR;a=;eR E E so oo oGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGdG]EwEAdd E;a eee;usO;iE;a o; E eu{+eu.tooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooeeeR =;n; ; ; ifooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo sOom+ E a 'o;Uu] aneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee;a; o; E nlae= l;nR;a=;eR E eH;'eA( FA^(oX daTfio;UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU